<?php
// +----------------------------------------------------------------------
// | KITEGO-Admin「开箱即用」「人人全栈」
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2024 https://www.kitego.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed KITEGO并不是自由软件，未经许可不能去掉KITEGO相关版权
// +----------------------------------------------------------------------
// | Author: KITEGO Team <bd@kitego.cn>
// +----------------------------------------------------------------------

namespace kitego\command;

use think\console\Command;
use think\console\Input;
use think\console\Output;
use ZipArchive;

class Patch extends Command
{
    protected $date;

    protected function configure()
    {
        $this->setName('补丁');
    }

    /**
     * 使用步骤
     * 1.将git patch文件上传到public/patch/20240804/20240804.patch
     * 2.app目录执行命令 php think patch
     * 3.public/patch目录下压缩包即为更新包
     *
     * @param Input $input
     * @param Output $output
     */
    protected function execute(Input $input, Output $output)
    {
        $this->date = date('Ymd', time());
        $patchContent = public_path() . 'patch' . DIRECTORY_SEPARATOR . $this->date . DIRECTORY_SEPARATOR . "$this->date.patch";
        $files = $this->parsePatchFiles($patchContent);

        $this->createDirectoryStructure($files);

        $output->writeln(PHP_EOL . 'PATCH SUCCESS');
    }

    protected function parsePatchFiles($patchContent): array
    {
        $files = [];
        // 尝试打开文件
        if (($handle = fopen($patchContent, "r")) !== FALSE) {
            // 逐行读取文件
            while (($line = fgets($handle)) !== FALSE) {
                // 使用正则表达式匹配以"Index:"开头的行
                if (preg_match('/^Index: (.*)$/', $line, $matches)) {
                    // 如果匹配成功，$matches[1]将包含Index后面的内容
                    $files[] = $matches[1];
                }
            }

            // 关闭文件
            fclose($handle);
        } else {
            // 文件打开失败
            echo "Unable to open file $patchContent";
        }

        return $files;
    }

    protected function createDirectoryStructure($files)
    {
        $targetFilePre = public_path() . 'patch' . DIRECTORY_SEPARATOR . $this->date . DIRECTORY_SEPARATOR;
        foreach ($files as $k => $file) {
            $sourceFile = dirname(root_path()) . DIRECTORY_SEPARATOR . $file;
            $targetFile = $targetFilePre . 'update' . $this->date . DIRECTORY_SEPARATOR . $file;
            $targetDir = dirname($targetFile);
            if (!file_exists($targetDir)) {
                mkdir($targetDir, 0777, true);
            }

            // 检查是否为文件（而不是目录）
            if (is_file($sourceFile)) {
                // 复制文件
                copy($sourceFile, $targetFile);

                echo $k . '复制完成' . PHP_EOL;
            }
        }

        // 生成压缩包
        $zip = new ZipArchive();
        $zipName = public_path() . 'patch' . DIRECTORY_SEPARATOR . $this->date . '|更新文件|解压源码目录即可|注意备份|谨慎操作.zip';
        $zipDir = dirname($zipName);
        if (!file_exists($zipDir)) {
            mkdir($zipDir, 0777, true);
        }

        if ($zip->open($zipName, ZipArchive::CREATE) === TRUE) {
            $directoryToZip = $targetFilePre;
            $this->addDirToZip($zip, $directoryToZip);
            $zip->close();

            echo "压缩完成，文件名为: " . $zipName;
        } else {
            echo "无法打开压缩文件 '$zipName' 来进行写入";
        }

        // 删除目录
        $this->deleteDirectory(public_path() . 'patch' . DIRECTORY_SEPARATOR . $this->date);
    }

    protected function addDirToZip($zip, $dir, $zipDir = '')
    {
        if (is_dir($dir)) {
            if ($zipDir == '') {
                $zip->addEmptyDir(basename($dir));
            } else {
                $zip->addEmptyDir($zipDir . '/' . basename($dir));
            }
            $zipDir .= '/' . basename($dir);

            $files = scandir($dir);

            foreach ($files as $file) {
                if ($file != '.' && $file != '..') {
                    $filePath = $dir . '/' . $file;

                    // 递归地添加目录
                    if (is_dir($filePath)) {
                        $this->addDirToZip($zip, $filePath, $zipDir);
                    } else {
                        // 添加文件
                        $zip->addFile($filePath, $zipDir . '/' . $file);
                    }
                }
            }
        }
    }

    protected function deleteDirectory($dirPath)
    {
        if (!file_exists($dirPath)) {
            return false;
        }

        $dir = opendir($dirPath);
        while ($fileName = readdir($dir)) {
            $file = $dirPath . '/' . $fileName;
            if ($fileName != '.' && $fileName != '..') {
                if (is_dir($file)) {
                    $this->deleteDirectory($file);
                } else {
                    unlink($file);
                }
            }
        }
        closedir($dir);

        return rmdir($dirPath);
    }
}